/*
 * Copyright (c) 2023-2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef LOG_TAG
#define LOG_TAG "CapturerInServer"
#endif

#include "capturer_in_server.h"
#include <cinttypes>
#include "securec.h"
#include "audio_errors.h"
#include "audio_utils.h"
#include "audio_capturer_log.h"
#include "audio_service.h"
#include "audio_process_config.h"
#include "i_stream_manager.h"
#ifdef HAS_FEATURE_INNERCAPTURER
#include "playback_capturer_manager.h"
#endif
#include "policy_handler.h"
#include "media_monitor_manager.h"
#include "audio_dump_pcm.h"
#include "volume_tools.h"
#include "core_service_handler.h"
#include "stream_dfx_manager.h"

namespace OHOS {
namespace AudioStandard {
namespace {
    static constexpr int32_t VOLUME_SHIFT_NUMBER = 16; // 1 >> 16 = 65536, max volume
    static const size_t CAPTURER_BUFFER_DEFAULT_NUM = 4;
    static const size_t CAPTURER_BUFFER_WAKE_UP_NUM = 100;
    static const uint32_t OVERFLOW_LOG_LOOP_COUNT = 100;
    constexpr int32_t RELEASE_TIMEOUT_IN_SEC = 10; // 10S
}

CapturerInServer::CapturerInServer(AudioProcessConfig processConfig, std::weak_ptr<IStreamListener> streamListener)
{
    processConfig_ = processConfig;
    streamListener_ = streamListener;
    innerCapId_ = processConfig.innerCapId;
    audioStreamChecker_ = std::make_shared<AudioStreamChecker>(processConfig);
    AudioStreamMonitor::GetInstance().AddCheckForMonitor(processConfig.originalSessionId, audioStreamChecker_);
}

CapturerInServer::~CapturerInServer()
{
    if (status_ != I_STATUS_RELEASED) {
        Release();
    }
    DumpFileUtil::CloseDumpFile(&dumpS2C_);
    if (needCheckBackground_) {
        TurnOffMicIndicator(CAPTURER_INVALID);
    }
}

int32_t CapturerInServer::ConfigServerBuffer()
{
    if (audioServerBuffer_ != nullptr) {
        AUDIO_INFO_LOG("ConfigProcessBuffer: process buffer already configed.");
        return SUCCESS;
    }
    CHECK_AND_RETURN_RET_LOG(stream_ != nullptr, ERR_OPERATION_FAILED, "ConfigServerBuffer failed, stream_ is null!");
    stream_->GetSpanSizePerFrame(spanSizeInFrame_);
    const size_t bufferNum = ((processConfig_.capturerInfo.sourceType == SOURCE_TYPE_WAKEUP)
        ? CAPTURER_BUFFER_WAKE_UP_NUM : CAPTURER_BUFFER_DEFAULT_NUM);
    totalSizeInFrame_ = spanSizeInFrame_ * bufferNum;
    stream_->GetByteSizePerFrame(byteSizePerFrame_);
    spanSizeInBytes_ = byteSizePerFrame_ * spanSizeInFrame_;
    AUDIO_INFO_LOG("ConfigProcessBuffer: totalSizeInFrame_: %{public}zu, spanSizeInFrame_: %{public}zu,"
        "byteSizePerFrame_: %{public}zu, spanSizeInBytes_ %{public}zu", totalSizeInFrame_, spanSizeInFrame_,
        byteSizePerFrame_, spanSizeInBytes_);
    if (totalSizeInFrame_ == 0 || spanSizeInFrame_ == 0 || totalSizeInFrame_ % spanSizeInFrame_ != 0) {
        AUDIO_ERR_LOG("ConfigProcessBuffer: ERR_INVALID_PARAM");
        return ERR_INVALID_PARAM;
    }

    int32_t ret = InitCacheBuffer(2 * spanSizeInBytes_);
    CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "InitCacheBuffer failed %{public}d", ret);

    // create OHAudioBuffer in server
    audioServerBuffer_ = OHAudioBuffer::CreateFromLocal(totalSizeInFrame_, spanSizeInFrame_, byteSizePerFrame_);
    CHECK_AND_RETURN_RET_LOG(audioServerBuffer_ != nullptr, ERR_OPERATION_FAILED, "Create oh audio buffer failed");

    // we need to clear data buffer to avoid dirty data.
    memset_s(audioServerBuffer_->GetDataBase(), audioServerBuffer_->GetDataSize(), 0,
        audioServerBuffer_->GetDataSize());
    ret = InitBufferStatus();
    AUDIO_DEBUG_LOG("Clear data buffer, ret:%{public}d", ret);
    isBufferConfiged_ = true;
    isInited_ = true;
    return SUCCESS;
}

int32_t CapturerInServer::InitBufferStatus()
{
    if (audioServerBuffer_ == nullptr) {
        AUDIO_ERR_LOG("InitBufferStatus failed, null buffer!");
        return ERR_ILLEGAL_STATE;
    }

    uint32_t spanCount = audioServerBuffer_->GetSpanCount();
    AUDIO_INFO_LOG("InitBufferStatus: spanCount %{public}u", spanCount);
    for (uint32_t i = 0; i < spanCount; i++) {
        SpanInfo *spanInfo = audioServerBuffer_->GetSpanInfoByIndex(i);
        if (spanInfo == nullptr) {
            AUDIO_ERR_LOG("InitBufferStatus failed, null spaninfo");
            return ERR_ILLEGAL_STATE;
        }
        spanInfo->spanStatus = SPAN_READ_DONE;
        spanInfo->offsetInFrame = 0;

        spanInfo->readStartTime = 0;
        spanInfo->readDoneTime = 0;

        spanInfo->readStartTime = 0;
        spanInfo->readDoneTime = 0;

        spanInfo->volumeStart = 1 << VOLUME_SHIFT_NUMBER; // 65536 for initialize
        spanInfo->volumeEnd = 1 << VOLUME_SHIFT_NUMBER; // 65536 for initialize
        spanInfo->isMute = false;
    }
    return SUCCESS;
}

int32_t CapturerInServer::Init()
{
    int32_t ret = IStreamManager::GetRecorderManager().CreateCapturer(processConfig_, stream_);
    CHECK_AND_RETURN_RET_LOG(ret == SUCCESS && stream_ != nullptr, ERR_OPERATION_FAILED,
        "Construct CapturerInServer failed: %{public}d", ret);
    streamIndex_ = stream_->GetStreamIndex();
    capturerClock_ = CapturerClockManager::GetInstance().CreateCapturerClock(
        streamIndex_, processConfig_.streamInfo.samplingRate);
    ret = ConfigServerBuffer();
    CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED, "ConfigServerBuffer failed: %{public}d", ret);
    stream_->RegisterStatusCallback(shared_from_this());
    stream_->RegisterReadCallback(shared_from_this());

    traceTag_ = "[" + std::to_string(streamIndex_) + "]CapturerServerOut"; // [100001]CapturerServerOut
    // eg: /data/data/.pulse_dir/10000_100009_capturer_server_out_48000_2_1.pcm
    AudioStreamInfo tempInfo = processConfig_.streamInfo;
    dumpFileName_ = std::to_string(processConfig_.appInfo.appPid) + "_" + std::to_string(streamIndex_)
        + "_capturer_server_out_" + std::to_string(tempInfo.samplingRate) + "_"
        + std::to_string(tempInfo.channels) + "_" + std::to_string(tempInfo.format) + ".pcm";
    DumpFileUtil::OpenDumpFile(DumpFileUtil::DUMP_SERVER_PARA, dumpFileName_, &dumpS2C_);
    recorderDfx_ = std::make_unique<RecorderDfxWriter>(processConfig_.appInfo, streamIndex_);
    AudioService::GetInstance()->RegisterMuteStateChangeCallback(streamIndex_, [this](bool flag) {
        AUDIO_INFO_LOG("recv mute state change flag %{public}d", flag ? 1 : 0);
        muteFlag_ = flag;
    });

    return SUCCESS;
}

// LCOV_EXCL_START
void CapturerInServer::OnStatusUpdate(IOperation operation)
{
    AUDIO_INFO_LOG("CapturerInServer::OnStatusUpdate operation: %{public}d", operation);
    operation_ = operation;
    if (status_ == I_STATUS_RELEASED) {
        AUDIO_WARNING_LOG("Stream already released");
        return;
    }
    std::shared_ptr<IStreamListener> stateListener = streamListener_.lock();
    CHECK_AND_RETURN_LOG((stateListener != nullptr && recorderDfx_ != nullptr), "IStreamListener is nullptr");
    switch (operation) {
        case OPERATION_UNDERFLOW:
            underflowCount += 1;
            AUDIO_INFO_LOG("Underflow!! underflow count %{public}d", underflowCount);
            break;
        case OPERATION_STARTED:
            status_ = I_STATUS_STARTED;
            lastStartTime_ = std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::system_clock::now().time_since_epoch()).count();
            stateListener->OnOperationHandled(START_STREAM, 0);
            break;
        case OPERATION_PAUSED:
            status_ = I_STATUS_PAUSED;
            stateListener->OnOperationHandled(PAUSE_STREAM, 0);
            HandleOperationStopped(CAPTURER_STAGE_PAUSE_OK);
            break;
        case OPERATION_STOPPED:
            status_ = I_STATUS_STOPPED;
            stateListener->OnOperationHandled(STOP_STREAM, 0);
            HandleOperationStopped(CAPTURER_STAGE_STOP_OK);
            break;
        case OPERATION_FLUSHED:
            HandleOperationFlushed();
            stateListener->OnOperationHandled(FLUSH_STREAM, 0);
            break;
        default:
            AUDIO_INFO_LOG("Invalid operation %{public}u", operation);
            status_ = I_STATUS_INVALID;
    }
}
// LCOV_EXCL_STOP

void CapturerInServer::HandleOperationFlushed()
{
    if (status_ == I_STATUS_FLUSHING_WHEN_STARTED) {
        status_ = I_STATUS_STARTED;
    } else if (status_ == I_STATUS_FLUSHING_WHEN_PAUSED) {
        status_ = I_STATUS_PAUSED;
    } else if (status_ == I_STATUS_FLUSHING_WHEN_STOPPED) {
        status_ = I_STATUS_STOPPED;
    } else {
        AUDIO_WARNING_LOG("Invalid status before flusing");
    }
}

void CapturerInServer::HandleOperationStopped(CapturerStage stage)
{
    CHECK_AND_RETURN_LOG(recorderDfx_ != nullptr, "nullptr");
    lastStopTime_ = std::chrono::duration_cast<std::chrono::milliseconds>(
        std::chrono::system_clock::now().time_since_epoch()).count();
    recorderDfx_->WriteDfxStopMsg(streamIndex_, stage,
        GetLastAudioDuration(), processConfig_);
}

BufferDesc CapturerInServer::DequeueBuffer(size_t length)
{
    return stream_->DequeueBuffer(length);
}

// LCOV_EXCL_START
bool CapturerInServer::IsReadDataOverFlow(size_t length, uint64_t currentWriteFrame,
    std::shared_ptr<IStreamListener> stateListener)
{
    if (audioServerBuffer_->GetWritableDataFrames() <= static_cast<int32_t>(spanSizeInFrame_)) {
        if (overFlowLogFlag_ == 0) {
            AUDIO_INFO_LOG("OverFlow!!!");
        } else if (overFlowLogFlag_ == OVERFLOW_LOG_LOOP_COUNT) {
            overFlowLogFlag_ = 0;
        }
        overFlowLogFlag_++;
        int32_t engineFlag = GetEngineFlag();
        if (engineFlag != 1) {
            BufferDesc dstBuffer = stream_->DequeueBuffer(length);
            stream_->EnqueueBuffer(dstBuffer);
        }
        return true;
    }
    return false;
}
// LCOV_EXCL_STOP

// LCOV_EXCL_START
static uint32_t GetByteSizeByFormat(enum AudioSampleFormat format)
{
    uint32_t byteSize = 0;
    switch (format) {
        case AudioSampleFormat::SAMPLE_U8:
            byteSize = BYTE_SIZE_SAMPLE_U8;
            break;
        case AudioSampleFormat::SAMPLE_S16LE:
            byteSize = BYTE_SIZE_SAMPLE_S16;
            break;
        case AudioSampleFormat::SAMPLE_S24LE:
            byteSize = BYTE_SIZE_SAMPLE_S24;
            break;
        case AudioSampleFormat::SAMPLE_S32LE:
            byteSize = BYTE_SIZE_SAMPLE_S32;
            break;
        case AudioSampleFormat::SAMPLE_F32LE:
            byteSize = BYTE_SIZE_SAMPLE_S32;
            break;
        default:
            byteSize = BYTE_SIZE_SAMPLE_S16;
            break;
    }
    return byteSize;
}
// LCOV_EXCL_STOP

void CapturerInServer::UpdateBufferTimeStamp(size_t readLen)
{
    uint64_t timestamp = 0;
    uint32_t sizePerPos = static_cast<uint32_t>(GetByteSizeByFormat(processConfig_.streamInfo.format)) *
        processConfig_.streamInfo.channels;

    curProcessPos_ += lastPosInc_;
    CHECK_AND_RETURN_LOG(readLen >= 0, "readLen is illegal!");
    lastPosInc_ = static_cast<uint64_t>(readLen) / sizePerPos;

    if (capturerClock_ != nullptr) {
        capturerClock_->GetTimeStampByPosition(curProcessPos_, timestamp);
    }

    AUDIO_DEBUG_LOG("update buffer timestamp pos:%{public}" PRIu64 " ts:%{public}" PRIu64,
        curProcessPos_, timestamp);
    audioServerBuffer_->SetTimeStampInfo(curProcessPos_, timestamp);
}

void CapturerInServer::RecordOverflowStatus(bool currentStatus)
{
    if (currentStatus == true && currentStatus != lastOverflowStatus_.load()) {
        lastOverflowStatus_.store(currentStatus);
        audioStreamChecker_->RecordOverflowTime(currentStatus);
    }
    if (currentStatus == false && currentStatus != lastOverflowStatus_.load()) {
        lastOverflowStatus_.store(currentStatus);
        audioStreamChecker_->RecordOverflowTime(currentStatus);
    }
}

// LCOV_EXCL_START
void CapturerInServer::ReadData(size_t length)
{
    CHECK_AND_RETURN_LOG(length >= spanSizeInBytes_,
        "Length %{public}zu is less than spanSizeInBytes %{public}zu", length, spanSizeInBytes_);
    std::shared_ptr<IStreamListener> stateListener = streamListener_.lock();
    CHECK_AND_RETURN_LOG(stateListener != nullptr, "IStreamListener is nullptr!");
    CHECK_AND_RETURN_LOG(stream_ != nullptr, "ReadData failed, stream_ is null!");

    uint64_t currentWriteFrame = audioServerBuffer_->GetCurWriteFrame();
    if (IsReadDataOverFlow(length, currentWriteFrame, stateListener)) {
        UpdateBufferTimeStamp(length);
        RecordOverflowStatus(true);
        return;
    }
    RecordOverflowStatus(false);
    Trace trace(traceTag_ + "::ReadData:" + std::to_string(currentWriteFrame));
    OptResult result = ringCache_->GetWritableSize();
    CHECK_AND_RETURN_LOG(result.ret == OPERATION_SUCCESS, "RingCache write invalid size %{public}zu", result.size);
    BufferDesc srcBuffer = stream_->DequeueBuffer(result.size);
    ringCache_->Enqueue({srcBuffer.buffer, srcBuffer.bufLength});
    result = ringCache_->GetReadableSize();
    if (result.ret != OPERATION_SUCCESS || result.size < spanSizeInBytes_) {
        stream_->EnqueueBuffer(srcBuffer);
        return;
    }

    BufferDesc dstBuffer = {nullptr, 0, 0};

    uint64_t curWritePos = audioServerBuffer_->GetCurWriteFrame();
    if (audioServerBuffer_->GetWriteBuffer(curWritePos, dstBuffer) < 0) {
        return;
    }

    if ((processConfig_.capturerInfo.sourceType == SOURCE_TYPE_PLAYBACK_CAPTURE && processConfig_.innerCapMode ==
        LEGACY_MUTE_CAP) || muteFlag_) {
        dstBuffer.buffer = dischargeBuffer_.get(); // discharge valid data.
    }

    if (muteFlag_) {
        memset_s(static_cast<void *>(dstBuffer.buffer), dstBuffer.bufLength, 0, dstBuffer.bufLength);
    }
    ringCache_->Dequeue({dstBuffer.buffer, dstBuffer.bufLength});
    VolumeTools::DfxOperation(dstBuffer, processConfig_.streamInfo, traceTag_, volumeDataCount_);
    if (AudioDump::GetInstance().GetVersionType() == DumpFileUtil::BETA_VERSION) {
        DumpFileUtil::WriteDumpFile(dumpS2C_, static_cast<void *>(dstBuffer.buffer), dstBuffer.bufLength);
        AudioCacheMgr::GetInstance().CacheData(dumpFileName_,
            static_cast<void *>(dstBuffer.buffer), dstBuffer.bufLength);
    }

    uint64_t nextWriteFrame = currentWriteFrame + spanSizeInFrame_;
    audioServerBuffer_->SetCurWriteFrame(nextWriteFrame);
    audioServerBuffer_->SetHandleInfo(currentWriteFrame, ClockTime::GetCurNano());

    UpdateBufferTimeStamp(dstBuffer.bufLength);

    stream_->EnqueueBuffer(srcBuffer);
}
// LCOV_EXCL_STOP

int32_t CapturerInServer::OnReadData(size_t length)
{
    Trace trace(traceTag_ + "::OnReadData:" + std::to_string(length));
    ReadData(length);
    return SUCCESS;
}

// LCOV_EXCL_START
int32_t CapturerInServer::OnReadData(int8_t *outputData, size_t requestDataLen)
{
    CHECK_AND_RETURN_RET_LOG(status_.load() == I_STATUS_STARTED, ERR_READ_FAILED, "CapturerInServer is not started");
    CHECK_AND_RETURN_RET_LOG(requestDataLen >= spanSizeInBytes_, ERR_READ_FAILED,
        "Length %{public}zu is less than spanSizeInBytes %{public}zu", requestDataLen, spanSizeInBytes_);
    std::shared_ptr<IStreamListener> stateListener = streamListener_.lock();
    CHECK_AND_RETURN_RET_LOG(stateListener != nullptr, ERR_READ_FAILED, "IStreamListener is nullptr!");
    uint64_t currentWriteFrame = audioServerBuffer_->GetCurWriteFrame();
    if (IsReadDataOverFlow(requestDataLen, currentWriteFrame, stateListener)) {
        UpdateBufferTimeStamp(requestDataLen);
        RecordOverflowStatus(true);
        return ERR_WRITE_FAILED;
    }
    RecordOverflowStatus(false);
    Trace trace("CapturerInServer::ReadData:" + std::to_string(currentWriteFrame));
    OptResult result = ringCache_->GetWritableSize();
    CHECK_AND_RETURN_RET_LOG(result.ret == OPERATION_SUCCESS, ERR_READ_FAILED,
        "RingCache write invalid size %{public}zu", result.size);

    BufferDesc srcBuffer = {reinterpret_cast<uint8_t *>(outputData), requestDataLen, 0};

    ringCache_->Enqueue({srcBuffer.buffer, srcBuffer.bufLength});
    result = ringCache_->GetReadableSize();
    if (result.ret != OPERATION_SUCCESS || result.size < spanSizeInBytes_) {
        return SUCCESS;
    }

    BufferDesc dstBuffer = {nullptr, 0, 0};
    uint64_t curWritePos = audioServerBuffer_->GetCurWriteFrame();
    CHECK_AND_RETURN_RET_LOG(audioServerBuffer_->GetWriteBuffer(curWritePos, dstBuffer) >= 0, ERR_READ_FAILED,
        "GetWriteBuffer failed");
    if ((processConfig_.capturerInfo.sourceType == SOURCE_TYPE_PLAYBACK_CAPTURE && processConfig_.innerCapMode ==
        LEGACY_MUTE_CAP) || muteFlag_) {
        dstBuffer.buffer = dischargeBuffer_.get(); // discharge valid data.
    }

    if (muteFlag_) {
        memset_s(static_cast<void *>(dstBuffer.buffer), dstBuffer.bufLength, 0, dstBuffer.bufLength);
    }
    ringCache_->Dequeue({dstBuffer.buffer, dstBuffer.bufLength});
    VolumeTools::DfxOperation(dstBuffer, processConfig_.streamInfo, traceTag_, volumeDataCount_);
    if (AudioDump::GetInstance().GetVersionType() == DumpFileUtil::BETA_VERSION) {
        DumpFileUtil::WriteDumpFile(dumpS2C_, static_cast<void *>(dstBuffer.buffer), dstBuffer.bufLength);
        AudioCacheMgr::GetInstance().CacheData(dumpFileName_,
            static_cast<void *>(dstBuffer.buffer), dstBuffer.bufLength);
    }

    uint64_t nextWriteFrame = currentWriteFrame + spanSizeInFrame_;
    audioServerBuffer_->SetCurWriteFrame(nextWriteFrame);
    audioServerBuffer_->SetHandleInfo(currentWriteFrame, ClockTime::GetCurNano());

    UpdateBufferTimeStamp(dstBuffer.bufLength);
    audioStreamChecker_->RecordNormalFrame();
    return SUCCESS;
}
// LCOV_EXCL_STOP

int32_t CapturerInServer::UpdateReadIndex()
{
    AUDIO_DEBUG_LOG("audioServerBuffer_->GetWritableDataFrames(): %{public}d, needStart: %{public}d",
        audioServerBuffer_->GetWritableDataFrames(), needStart);
    return SUCCESS;
}

int32_t CapturerInServer::ResolveBuffer(std::shared_ptr<OHAudioBuffer> &buffer)
{
    buffer = audioServerBuffer_;
    return SUCCESS;
}

int32_t CapturerInServer::GetSessionId(uint32_t &sessionId)
{
    CHECK_AND_RETURN_RET_LOG(stream_ != nullptr, ERR_OPERATION_FAILED, "GetSessionId failed, stream_ is null");
    sessionId = streamIndex_;
    CHECK_AND_RETURN_RET_LOG(sessionId < INT32_MAX, ERR_OPERATION_FAILED, "GetSessionId failed, sessionId:%{public}d",
        sessionId);

    return SUCCESS;
}

bool CapturerInServer::CheckBGCapture()
{
    uint32_t tokenId = processConfig_.appInfo.appTokenId;
    uint64_t fullTokenId = processConfig_.appInfo.appFullTokenId;

    if (PermissionUtil::VerifyBackgroundCapture(tokenId, fullTokenId)) {
        return true;
    }

    CHECK_AND_RETURN_RET_LOG(Util::IsBackgroundSourceType(processConfig_.capturerInfo.sourceType) &&
        AudioService::GetInstance()->InForegroundList(processConfig_.appInfo.appUid), false, "Check failed");

    AudioService::GetInstance()->UpdateForegroundState(tokenId, true);
    bool res = PermissionUtil::VerifyBackgroundCapture(tokenId, fullTokenId);
    AUDIO_INFO_LOG("Retry result:%{public}s", (res ? "success" : "fail"));
    AudioService::GetInstance()->UpdateForegroundState(tokenId, false);

    return res;
}

bool CapturerInServer::TurnOnMicIndicator(CapturerState capturerState)
{
    uint32_t tokenId = processConfig_.appInfo.appTokenId;
    SwitchStreamInfo info = {
        streamIndex_,
        processConfig_.callerUid,
        processConfig_.appInfo.appUid,
        processConfig_.appInfo.appPid,
        tokenId,
        capturerState,
    };
    if (!SwitchStreamUtil::IsSwitchStreamSwitching(info, SWITCH_STATE_STARTED)) {
        CHECK_AND_RETURN_RET_LOG(CheckBGCapture(), false, "Verify failed");
    }
    SwitchStreamUtil::UpdateSwitchStreamRecord(info, SWITCH_STATE_STARTED);

    if (isMicIndicatorOn_) {
        AUDIO_WARNING_LOG("MicIndicator:already on, Stream:%{public}u.", streamIndex_);
    } else {
        CHECK_AND_RETURN_RET_LOG(PermissionUtil::NotifyPrivacyStart(tokenId, streamIndex_),
            false, "NotifyPrivacyStart failed!");
        AUDIO_INFO_LOG("MicIndicator:turn on,Stream:%{public}u", streamIndex_);
        isMicIndicatorOn_ = true;
    }
    return true;
}

bool CapturerInServer::TurnOffMicIndicator(CapturerState capturerState)
{
    uint32_t tokenId = processConfig_.appInfo.appTokenId;
    SwitchStreamInfo info = {
        streamIndex_,
        processConfig_.callerUid,
        processConfig_.appInfo.appUid,
        processConfig_.appInfo.appPid,
        tokenId,
        capturerState,
    };
    SwitchStreamUtil::UpdateSwitchStreamRecord(info, SWITCH_STATE_FINISHED);
    if (isMicIndicatorOn_) {
        PermissionUtil::NotifyPrivacyStop(tokenId, streamIndex_);
        AUDIO_INFO_LOG("MicIndicator:turn off, Stream:%{public}u", streamIndex_);
        isMicIndicatorOn_ = false;
    } else {
        AUDIO_WARNING_LOG("MicIndicator:already off, Stream:%{public}u", streamIndex_);
    }
    return true;
}

int32_t CapturerInServer::Start()
{
    AudioXCollie audioXCollie(
        "CapturerInServer::Start", RELEASE_TIMEOUT_IN_SEC, nullptr, nullptr,
            AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
    int32_t ret = StartInner();
    CapturerStage stage = ret == SUCCESS ? CAPTURER_STAGE_START_OK : CAPTURER_STAGE_START_FAIL;
    if (recorderDfx_) {
        recorderDfx_->WriteDfxStartMsg(streamIndex_, stage, processConfig_);
    }
    if (ret == SUCCESS) {
        StreamDfxManager::GetInstance().CheckStreamOccupancy(streamIndex_, processConfig_, true);
        CaptureConcurrentCheck(streamIndex_);
    }
    audioStreamChecker_->MonitorOnAllCallback(AUDIO_STREAM_START, false);
    return ret;
}

// LCOV_EXCL_START
int32_t CapturerInServer::StartInner()
{
    needStart = 0;
    std::unique_lock<std::mutex> lock(statusLock_);

    if (status_ != I_STATUS_IDLE && status_ != I_STATUS_PAUSED && status_ != I_STATUS_STOPPED) {
        AUDIO_ERR_LOG("CapturerInServer::Start failed, Illegal state: %{public}u", status_.load());
        return ERR_ILLEGAL_STATE;
    }

    if (!needCheckBackground_ && PermissionUtil::NeedVerifyBackgroundCapture(processConfig_.callerUid,
        processConfig_.capturerInfo.sourceType)) {
        AUDIO_INFO_LOG("set needCheckBackground_: true");
        needCheckBackground_ = true;
    }
    if (needCheckBackground_) {
        CHECK_AND_RETURN_RET_LOG(TurnOnMicIndicator(CAPTURER_RUNNING), ERR_PERMISSION_DENIED,
            "Turn on micIndicator failed or check backgroud capture failed for stream:%{public}d!", streamIndex_);
    }
    AudioService::GetInstance()->NotifyVoIPStart(processConfig_.capturerInfo.sourceType, processConfig_.appInfo.appUid);

    if (processConfig_.capturerInfo.sourceType != SOURCE_TYPE_PLAYBACK_CAPTURE) {
        CoreServiceHandler::GetInstance().UpdateSessionOperation(streamIndex_, SESSION_OPERATION_START);
    }

    if (CoreServiceHandler::GetInstance().ReloadCaptureSession(streamIndex_, SESSION_OPERATION_START) == SUCCESS) {
        AUDIO_ERR_LOG("ReloadCaptureSession success!");
    }

    status_ = I_STATUS_STARTING;
    if (processConfig_.capturerInfo.sourceType == SOURCE_TYPE_PLAYBACK_CAPTURE) {
        PlaybackCapturerManager::GetInstance()->InitAllDupBuffer(innerCapId_);
    }
    int32_t ret = stream_->Start();
    CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "Start stream failed, reason: %{public}d", ret);
    resetTime_ = true;
    RebuildCaptureInjector();

    if (capturerClock_ != nullptr) {
        capturerClock_->Start();
    }

    return SUCCESS;
}
// LCOV_EXCL_STOP

void CapturerInServer::RebuildCaptureInjector()
{
    CHECK_AND_RETURN_LOG(rebuildFlag_, "no need to rebuild");
    if (processConfig_.capturerInfo.sourceType == SOURCE_TYPE_VOICE_COMMUNICATION) {
        CoreServiceHandler::GetInstance().RebuildCaptureInjector(streamIndex_);
    }
    rebuildFlag_ = false;
}

// LCOV_EXCL_START
int32_t CapturerInServer::Pause()
{
    AudioXCollie audioXCollie(
        "CapturerInServer::Pause", RELEASE_TIMEOUT_IN_SEC, nullptr, nullptr,
            AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
    std::unique_lock<std::mutex> lock(statusLock_);

    if (status_ != I_STATUS_STARTED) {
        AUDIO_ERR_LOG("failed, Illegal state: %{public}u", status_.load());
        return ERR_ILLEGAL_STATE;
    }
    if (needCheckBackground_) {
        TurnOffMicIndicator(CAPTURER_PAUSED);
    }
    if (CoreServiceHandler::GetInstance().ReloadCaptureSession(streamIndex_, SESSION_OPERATION_PAUSE) == SUCCESS) {
        AUDIO_INFO_LOG("ReloadCaptureSession success!");
    }

    status_ = I_STATUS_PAUSING;
    int ret = stream_->Pause();
    CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "Pause stream failed, reason: %{public}d", ret);
    CoreServiceHandler::GetInstance().UpdateSessionOperation(streamIndex_, SESSION_OPERATION_PAUSE);
    StreamDfxManager::GetInstance().CheckStreamOccupancy(streamIndex_, processConfig_, false);
    CaptureConcurrentCheck(streamIndex_);
    if (capturerClock_ != nullptr) {
        capturerClock_->Stop();
    }
    audioStreamChecker_->MonitorOnAllCallback(AUDIO_STREAM_PAUSE, false);
    return SUCCESS;
}
// LCOV_EXCL_STOP

int32_t CapturerInServer::Flush()
{
    AudioXCollie audioXCollie(
        "CapturerInServer::Flush", RELEASE_TIMEOUT_IN_SEC, nullptr, nullptr,
            AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
    std::unique_lock<std::mutex> lock(statusLock_);
    if (status_ == I_STATUS_STARTED) {
        status_ = I_STATUS_FLUSHING_WHEN_STARTED;
    } else if (status_ == I_STATUS_PAUSED) {
        status_ = I_STATUS_FLUSHING_WHEN_PAUSED;
    } else if (status_ == I_STATUS_STOPPED) {
        status_ = I_STATUS_FLUSHING_WHEN_STOPPED;
    } else {
        AUDIO_ERR_LOG("failed, Illegal state: %{public}u", status_.load());
        return ERR_ILLEGAL_STATE;
    }

    // Flush buffer of audio server
    uint64_t writeFrame = audioServerBuffer_->GetCurWriteFrame();
    uint64_t readFrame = audioServerBuffer_->GetCurReadFrame();

    while (readFrame < writeFrame) {
        BufferDesc bufferDesc = {nullptr, 0, 0};
        int32_t readResult = audioServerBuffer_->GetReadbuffer(readFrame, bufferDesc);
        if (readResult != 0) {
            return ERR_OPERATION_FAILED;
        }
        memset_s(bufferDesc.buffer, bufferDesc.bufLength, 0, bufferDesc.bufLength);
        readFrame += spanSizeInFrame_;
        AUDIO_INFO_LOG("On flush, write frame: %{public}" PRIu64 ", nextReadFrame: %{public}zu,"
            "readFrame: %{public}" PRIu64 "", writeFrame, spanSizeInFrame_, readFrame);
        audioServerBuffer_->SetCurReadFrame(readFrame);
    }

    int ret = stream_->Flush();
    CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "Flush stream failed, reason: %{public}d", ret);
    return SUCCESS;
}

int32_t CapturerInServer::DrainAudioBuffer()
{
    return SUCCESS;
}

// LCOV_EXCL_START
int32_t CapturerInServer::Stop()
{
    AudioXCollie audioXCollie(
        "CapturerInServer::Stop", RELEASE_TIMEOUT_IN_SEC, nullptr, nullptr,
            AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
    std::unique_lock<std::mutex> lock(statusLock_);
    if (status_ != I_STATUS_STARTED && status_ != I_STATUS_PAUSED) {
        AUDIO_ERR_LOG("failed, Illegal state: %{public}u", status_.load());
        return ERR_ILLEGAL_STATE;
    }
    status_ = I_STATUS_STOPPING;

    if (capturerClock_ != nullptr) {
        capturerClock_->Stop();
    }
    if (needCheckBackground_) {
        TurnOffMicIndicator(CAPTURER_STOPPED);
    }
    if (CoreServiceHandler::GetInstance().ReloadCaptureSession(streamIndex_, SESSION_OPERATION_STOP) == SUCCESS) {
        AUDIO_INFO_LOG("ReloadCaptureSession success!");
    }

    int ret = stream_->Stop();
    CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "Stop stream failed, reason: %{public}d", ret);
    CoreServiceHandler::GetInstance().UpdateSessionOperation(streamIndex_, SESSION_OPERATION_STOP);
    StreamDfxManager::GetInstance().CheckStreamOccupancy(streamIndex_, processConfig_, false);
    CaptureConcurrentCheck(streamIndex_);
    audioStreamChecker_->MonitorOnAllCallback(AUDIO_STREAM_STOP, false);
    return SUCCESS;
}
// LCOV_EXCL_STOP

int32_t CapturerInServer::Release(bool isSwitchStream)
{
    AudioXCollie audioXCollie("CapturerInServer::Release", RELEASE_TIMEOUT_IN_SEC,
        nullptr, nullptr, AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
    AudioService::GetInstance()->RemoveCapturer(streamIndex_, isSwitchStream);
    std::unique_lock<std::mutex> lock(statusLock_);
    if (status_ == I_STATUS_RELEASED) {
        AUDIO_INFO_LOG("Already released");
        return SUCCESS;
    }
    lock.unlock();
    AUDIO_INFO_LOG("Start release capturer");
    AudioStreamMonitor::GetInstance().DeleteCheckForMonitor(processConfig_.originalSessionId);

    if (processConfig_.capturerInfo.sourceType != SOURCE_TYPE_PLAYBACK_CAPTURE) {
        int32_t result =
            CoreServiceHandler::GetInstance().UpdateSessionOperation(streamIndex_, SESSION_OPERATION_RELEASE);
        CHECK_AND_RETURN_RET_LOG(result == SUCCESS, result, "Policy remove client failed, reason: %{public}d", result);
    }
    StreamDfxManager::GetInstance().CheckStreamOccupancy(streamIndex_, processConfig_, false);
    CaptureConcurrentCheck(streamIndex_);
    int32_t ret = IStreamManager::GetRecorderManager().ReleaseCapturer(streamIndex_);
    if (ret < 0) {
        AUDIO_ERR_LOG("Release stream failed, reason: %{public}d", ret);
        status_ = I_STATUS_INVALID;
        return ret;
    }

    ReleaseCaptureInjector();
    if (status_ != I_STATUS_STOPPING &&
        status_ != I_STATUS_STOPPED) {
        HandleOperationStopped(CAPTURER_STAGE_STOP_BY_RELEASE);
    }
    if (CoreServiceHandler::GetInstance().ReloadCaptureSession(streamIndex_, SESSION_OPERATION_RELEASE) == SUCCESS) {
        AUDIO_INFO_LOG("ReloadCaptureSession success!");
    }
    status_ = I_STATUS_RELEASED;

    CapturerClockManager::GetInstance().DeleteCapturerClock(streamIndex_);
#ifdef HAS_FEATURE_INNERCAPTURER
    if (processConfig_.capturerInfo.sourceType == SOURCE_TYPE_PLAYBACK_CAPTURE) {
        AUDIO_INFO_LOG("Disable inner capturer for %{public}u, innerCapId :%{public}d, innerCapMode:%{public}d",
            streamIndex_, innerCapId_, processConfig_.innerCapMode);
        if (processConfig_.innerCapMode == MODERN_INNER_CAP) {
            PlaybackCapturerManager::GetInstance()->RemovePlaybackCapturerFilterInfo(streamIndex_, innerCapId_);
        } else {
            PlaybackCapturerManager::GetInstance()->SetInnerCapturerState(false);
        }
        if (PlaybackCapturerManager::GetInstance()->CheckReleaseUnloadModernInnerCapSink(innerCapId_)) {
            AudioService::GetInstance()->UnloadModernInnerCapSink(innerCapId_);
        }
        if (PlaybackCapturerManager::GetInstance()->CheckReleaseUnloadModernOffloadCapSource()) {
            AudioService::GetInstance()->UnloadModernOffloadCapSource();
        }
        innerCapId_ = 0;
    }
#endif
    if (needCheckBackground_) {
        TurnOffMicIndicator(CAPTURER_RELEASED);
    }
    return SUCCESS;
}

void CapturerInServer::ReleaseCaptureInjector()
{
    if (processConfig_.capturerInfo.sourceType == SOURCE_TYPE_VOICE_COMMUNICATION) {
        CoreServiceHandler::GetInstance().ReleaseCaptureInjector();
    }
}

#ifdef HAS_FEATURE_INNERCAPTURER
int32_t CapturerInServer::UpdatePlaybackCaptureConfigInLegacy(const AudioPlaybackCaptureConfig &config)
{
    Trace trace("UpdatePlaybackCaptureConfigInLegacy");
    // Legacy mode, only usage filter works.
    AUDIO_INFO_LOG("Update config in legacy mode with %{public}zu usage", config.filterOptions.usages.size());

    std::vector<int32_t> usage;
    for (size_t i = 0; i < config.filterOptions.usages.size(); i++) {
        usage.push_back(config.filterOptions.usages[i]);
    }

    PlaybackCapturerManager::GetInstance()->SetSupportStreamUsage(usage);
    PlaybackCapturerManager::GetInstance()->SetInnerCapturerState(true);
    return SUCCESS;
}

int32_t CapturerInServer::UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config)
{
    Trace trace("UpdatePlaybackCaptureConfig:" + ProcessConfig::DumpInnerCapConfig(config));
    std::lock_guard<std::mutex> lock(filterConfigLock_);
    CHECK_AND_RETURN_RET_LOG(processConfig_.capturerInfo.sourceType == SOURCE_TYPE_PLAYBACK_CAPTURE,
        ERR_INVALID_OPERATION, "This not a inner-cap source!");

    AUDIO_INFO_LOG("Client using config: %{public}s", ProcessConfig::DumpInnerCapConfig(config).c_str());

    for (auto &usg : config.filterOptions.usages) {
        if (usg != STREAM_USAGE_VOICE_COMMUNICATION) {
            continue;
        }

        if (!PermissionUtil::VerifyPermission(CAPTURER_VOICE_DOWNLINK_PERMISSION, processConfig_.appInfo.appTokenId)) {
            AUDIO_ERR_LOG("downlink capturer permission check failed");
            return ERR_PERMISSION_DENIED;
        }
    }
    filterConfig_ = config;

    if (filterConfig_.filterOptions.usages.size() == 0) {
        std::vector<StreamUsage> defalutUsages = PlaybackCapturerManager::GetInstance()->GetDefaultUsages();
        for (size_t i = 0; i < defalutUsages.size(); i++) {
            filterConfig_.filterOptions.usages.push_back(defalutUsages[i]);
        }
        AUDIO_INFO_LOG("Reset config to %{public}s", ProcessConfig::DumpInnerCapConfig(filterConfig_).c_str());
    }

    if (processConfig_.innerCapMode != MODERN_INNER_CAP) {
        return UpdatePlaybackCaptureConfigInLegacy(filterConfig_);
    }

    // in plan: add more check and print config
    PlaybackCapturerManager::GetInstance()->SetPlaybackCapturerFilterInfo(streamIndex_, filterConfig_, innerCapId_);
    return SUCCESS;
}
#endif

// LCOV_EXCL_START
int32_t CapturerInServer::GetAudioTime(uint64_t &framePos, uint64_t &timestamp)
{
    if (status_ == I_STATUS_STOPPED) {
        AUDIO_WARNING_LOG("Current status is stopped");
        return ERR_ILLEGAL_STATE;
    }
    CHECK_AND_RETURN_RET_LOG(stream_ != nullptr, ERR_OPERATION_FAILED, "GetAudioTime failed, stream_ is null");
    stream_->GetStreamFramesRead(framePos);
    stream_->GetCurrentTimeStamp(timestamp);
    if (resetTime_) {
        resetTime_ = false;
        resetTimestamp_ = timestamp;
    }
    return SUCCESS;
}
// LCOV_EXCL_STOP

int32_t CapturerInServer::GetLatency(uint64_t &latency)
{
    CHECK_AND_RETURN_RET_LOG(stream_ != nullptr, ERR_OPERATION_FAILED, "GetLatency failed, stream_ is null");
    return stream_->GetLatency(latency);
}

int32_t CapturerInServer::InitCacheBuffer(size_t targetSize)
{
    CHECK_AND_RETURN_RET_LOG(spanSizeInBytes_ != 0, ERR_OPERATION_FAILED, "spanSizeInByte_ invalid");

    AUDIO_INFO_LOG("old size:%{public}zu, new size:%{public}zu", cacheSizeInBytes_, targetSize);
    cacheSizeInBytes_ = targetSize;

    if (ringCache_ == nullptr) {
        ringCache_ = AudioRingCache::Create(cacheSizeInBytes_);
    } else {
        OptResult result = ringCache_->ReConfig(cacheSizeInBytes_, false); // false --> clear buffer
        if (result.ret != OPERATION_SUCCESS) {
            AUDIO_ERR_LOG("ReConfig AudioRingCache to size %{public}u failed:ret%{public}zu", result.ret, targetSize);
            return ERR_OPERATION_FAILED;
        }
    }

    if (processConfig_.capturerInfo.sourceType == SOURCE_TYPE_PLAYBACK_CAPTURE && processConfig_.innerCapMode ==
        LEGACY_MUTE_CAP) {
        dischargeBuffer_ = std::make_unique<uint8_t []>(cacheSizeInBytes_);
    }

    return SUCCESS;
}

void CapturerInServer::SetNonInterruptMute(const bool muteFlag)
{
    AUDIO_INFO_LOG("muteFlag: %{public}d", muteFlag);
    muteFlag_ = muteFlag;
    AudioService::GetInstance()->UpdateMuteControlSet(streamIndex_, muteFlag);
}

RestoreStatus CapturerInServer::RestoreSession(RestoreInfo restoreInfo)
{
    RestoreStatus restoreStatus = audioServerBuffer_->SetRestoreStatus(NEED_RESTORE);
    if (restoreStatus == NEED_RESTORE) {
        SwitchStreamInfo info = {
            streamIndex_,
            processConfig_.callerUid,
            processConfig_.appInfo.appUid,
            processConfig_.appInfo.appPid,
            processConfig_.appInfo.appTokenId,
            status_.load() == I_STATUS_STARTED ? CAPTURER_RUNNING : CAPTURER_PREPARED
        };
        AUDIO_INFO_LOG("Insert switchStream:%{public}u uid:%{public}d tokenId:%{public}u "
            "Reason:NEED_RESTORE", streamIndex_, info.callerUid, info.appTokenId);
        SwitchStreamUtil::UpdateSwitchStreamRecord(info, SWITCH_STATE_WAITING);

        audioServerBuffer_->SetRestoreInfo(restoreInfo);
        audioServerBuffer_->WakeFutex(IS_PRE_EXIT);
    }
    return restoreStatus;
}

void  CapturerInServer::SetRebuildFlag()
{
    rebuildFlag_ = true;
}

int64_t CapturerInServer::GetLastAudioDuration()
{
    auto ret = lastStopTime_ - lastStartTime_;
    return ret < 0 ? -1 : ret;
}

int32_t CapturerInServer::StopSession()
{
    CHECK_AND_RETURN_RET_LOG(audioServerBuffer_ != nullptr, ERR_INVALID_PARAM, "audioServerBuffer_ is nullptr");
    audioServerBuffer_->SetStopFlag(true);
    return SUCCESS;
}

int32_t CapturerInServer::ResolveBufferBaseAndGetServerSpanSize(std::shared_ptr<OHAudioBufferBase> &buffer,
    uint32_t &spanSizeInFrame, uint64_t &engineTotalSizeInFrame)
{
    return ERR_NOT_SUPPORTED;
}

// LCOV_EXCL_START
inline void CapturerInServer::CaptureConcurrentCheck(uint32_t streamIndex)
{
    if (lastStatus_ == status_) {
        return;
    }
    std::atomic_store(&lastStatus_, status_);
    int32_t ret = CoreServiceHandler::GetInstance().CaptureConcurrentCheck(streamIndex);
    AUDIO_INFO_LOG("ret:%{public}d streamIndex_:%{public}d status_:%{public}u", ret, streamIndex, status_.load());
}
// LCOV_EXCL_STOP
} // namespace AudioStandard
} // namespace OHOS
